package org.honeynet.hbbackend.ipfilter;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.annotation.Resource;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.EJB;
import javax.ejb.EJBException;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenContext;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@MessageDriven(
		mappedName = "jms/new_attack",
		activationConfig = {
				@ActivationConfigProperty(propertyName="subscriptionDurability", propertyValue="Durable"),
				@ActivationConfigProperty(propertyName="subscriptionName", propertyValue="ipfilter"),
				@ActivationConfigProperty(propertyName="clientId", propertyValue="ipfilter")
		}
)
public class Filter implements MessageListener {

		private final static Logger log = LoggerFactory.getLogger(Filter.class);
		
		@Resource(mappedName="jdbc/hbbackend")
		private DataSource ds;
		
		@Resource(mappedName="jms/new_ip")
		private Destination jms_new_ip;
		
		@Resource(mappedName="jms/ConnectionFactory")
		private ConnectionFactory jmsConnectionFactory;;
		
		@Resource
	    private MessageDrivenContext mctx;
		
		@EJB
		Cache cache;

		@Override
		public void onMessage(Message msg) {
			log.trace("onMessage() called");
			
			try {
				String[] ips = new String[] {
//					msg.getStringProperty("senor_ip"), //TODO
					msg.getStringProperty("source_ip"),
					msg.getStringProperty("target_ip")
				};
				
				for (String ip : ips) {
					log.trace("looking up ip in cache: {}", ip);
					if (cache.contains(ip)) {
						log.trace("ip found in cache: {}", ip);
					}
					else {
						work(ip, false);
						log.trace("work() returned");
						cache.add(ip);
					}
				}
				
				return;
				
			} catch (JMSException e) {
				log.error("got JMSException", e);
				throw new EJBException(e);
			}
		}
		

		@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
		public boolean work(String ip, boolean sensor) {
			log.trace("work() called");
			
			Connection db = null;
			javax.jms.Connection mq = null;
			Session sess = null;
			MessageProducer prod = null;
			
			PreparedStatement pStmt;
			ResultSet queryRes;
			
			try {
				db = ds.getConnection();
				
				pStmt = db.prepareStatement("select * from safe_insert_ip(inet(?))");
				pStmt.setString(1, ip);
				queryRes = pStmt.executeQuery();
				queryRes.next();
				boolean inserted = queryRes.getBoolean(1);
				
				queryRes.close();
				pStmt.close();
				
				log.trace("safe_insert_ip returned {} (ip = {})", inserted, ip);
				
				// if inserted it must be unique and message can be sent
				if (inserted) {
					// if (sensor == true)
					
					mq = jmsConnectionFactory.createConnection();
					sess = mq.createSession(true, 0);
					prod = sess.createProducer(jms_new_ip);
					
					Message jmsMsg = sess.createMessage();
					jmsMsg.setJMSType("unique");
					jmsMsg.setStringProperty("ip", ip);
					
					prod.send(jmsMsg);
					log.trace("scheduled sending '{}' to new_ip", ip);
				}
				
				return inserted;
				
			} catch (SQLException e) {
				log.error("got SQLException", e);
				throw new EJBException(e);
			} catch (JMSException e) {
				log.error("got JMSException", e);
				throw new EJBException(e);
			} finally {
				try {
					if (mq != null) mq.close();
					if (db != null)	db.close();
				} catch (SQLException e) {
					log.error("got SQLException", e);
					throw new EJBException(e);
				} catch (JMSException e) {
					log.error("got JMSException", e);
					throw new EJBException(e);
				}
			}
		}
}
